package com.icehand.redis.config;


import com.icehand.redis.bloom.RedisBloomFilter;
import com.icehand.redis.interceptor.LockMethodInterceptor;
import com.icehand.redis.key.CacheKeyGenerator;
import com.icehand.redis.key.LockKeyGenerator;
import com.icehand.redis.serializer.FastJsonRedisSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * @author icehand
 */
@Slf4j
@EnableCaching
@EnableConfigurationProperties(value = RedisBloomFilterProperties.class)
public class RedisConfiguration {
    @Autowired
    private RedisBloomFilterProperties redisBloomFilterProperties;

    @Bean
    public FastJsonRedisSerializer fastJsonRedisSerializer(){
        return new FastJsonRedisSerializer<>(Object.class);
    }

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory,
                                       FastJsonRedisSerializer fastJsonRedisSerializer) {
        log.info("Initializing redisTemplate with fastjson serializer");
        RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory, FastJsonRedisSerializer<Object> fastJsonRedisSerializer) {
        log.info("Initializing cacheManager");
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer))
                .disableCachingNullValues()
                .entryTtl(Duration.ofDays(7));
        return RedisCacheManager.builder(factory).cacheDefaults(config).build();
    }

    @Bean
    @ConditionalOnMissingBean
    public CacheKeyGenerator cacheKeyGenerator() {
        return new LockKeyGenerator();
    }

    @Bean
    public LockMethodInterceptor lockMethodInterceptor(StringRedisTemplate redisTemplate, CacheKeyGenerator cacheKeyGenerator){
        log.info("Initializing lockMethodInterceptor");
        return new LockMethodInterceptor(redisTemplate, cacheKeyGenerator);
    }

    @Bean
    public RedisBloomFilter redisBloomFilter(RedisTemplate redisTemplate){
        if(null == redisBloomFilterProperties){
            return new RedisBloomFilter(redisTemplate);
        }
        return new RedisBloomFilter(redisTemplate,redisBloomFilterProperties.getInsertions(),redisBloomFilterProperties.getFpp(),
                redisBloomFilterProperties.getKeyPrefix());
    }
}
